package com.vpx.server.service.system.impl;

import com.vpx.server.bean.constant.HashMapSizeConstant;
import com.vpx.server.bean.entity.*;
import com.vpx.server.bean.enums.MenuTypeEnum;
import com.vpx.server.bean.info.system.MenuOperateInfo;
import com.vpx.server.bean.info.system.MenuTreeInfo;
import com.vpx.server.bean.info.system.SysUserInfo;
import com.vpx.server.bean.info.system.UserDetailInfo;
import com.vpx.server.bean.info.system.UserRoleInfo;
import com.vpx.server.bean.order.authority.LoginOrder;
import com.vpx.server.bean.result.system.AuthMenuResult;
import com.vpx.server.bean.result.system.UserDetailResult;
import com.vpx.server.framework.aop.ServiceHandler;
import com.vpx.server.framework.authority.SessionUser;
import com.vpx.server.framework.authority.SessionUtil;
import com.vpx.server.framework.base.ResultMsg;
import com.vpx.server.framework.utils.PasswordUtil;
import com.vpx.server.mapper.system.AuthorityMapper;
import com.vpx.server.mapper.system.SysMenuOperateMapper;
import com.vpx.server.mapper.system.SysUserMapper;
import com.vpx.server.service.system.AuthorityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author lihui
 * @title: vpx
 * @module
 * @description: TODO
 * @date 2021/9/11 17:51
 */
@Service
public class AuthorityServiceImpl implements AuthorityService {
    @Autowired
    AuthorityMapper authorityMapper;

    @Autowired
    SysMenuOperateMapper sysMenuOperateMapper;
    
    @Autowired
    SysUserMapper sysUserMapper;

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    @ServiceHandler(memo = "用户登录",type = "用户登陆")
    public ResultMsg login(LoginOrder order) {
        SysUser sysUser = authorityMapper.queryUserByLoginNum(order.getLoginAccount());
        if(sysUser == null){
            return ResultMsg.fail("用户名或密码错误！");
        }

        if(!sysUser.getLoginPwd().equals(PasswordUtil.getPassword(order.getLoginPwd()))){
            return ResultMsg.fail("用户名或密码错误！");
        }

        List<SysRole> roleList = authorityMapper.queryUserRoles(sysUser.getId());

        Set<String> auths = new HashSet<String>();
        for(SysRole role : roleList){
            List<SysMenuOperate> authList = authorityMapper.queryUserAuth(role.getId());
            for(SysMenuOperate operate : authList){
                auths.add(operate.getOperateUrl());
            }
        }


        SessionUser sessionUser = new SessionUser();
        BeanUtils.copyProperties(sysUser, sessionUser);

        sessionUser.setRoleList(roleList);
        sessionUser.setAuths(auths);

        SessionUtil.getSession().putSessionUser(sessionUser);
        return new ResultMsg();
    }

    @Override
	public ResultMsg<UserDetailResult> queryUserInfo(Long userId) {
    	SysUser sysUser = sysUserMapper.selectById(userId);
    	UserDetailInfo userDetailInfo = new UserDetailInfo();
    	userDetailInfo.from(sysUser);
    	
    	List<UserRoleInfo> userRoleList = new ArrayList<UserRoleInfo>();
    	
    	List<SysRole> roleList = authorityMapper.queryUserRoles(sysUser.getId());

        Set<String> authBtnCodes = new HashSet<String>();
        for(SysRole role : roleList){
        	UserRoleInfo userRoleInfo = new UserRoleInfo();
        	userRoleInfo.from(role);
        	userRoleInfo.setRoleId(role.getId());
        	userRoleInfo.setHasRoleAuth(true);
        	userRoleList.add(userRoleInfo);
        	
            List<SysMenuOperate> authList = authorityMapper.queryUserAuth(role.getId());
            for(SysMenuOperate operate : authList){
            	authBtnCodes.add(operate.getCode());
            }
        }
        
        userDetailInfo.setAuthBtnCodes(authBtnCodes);
        userDetailInfo.setRoleList(userRoleList);
        
    	
        UserDetailResult result = new UserDetailResult();
        result.setUserDetailInfo(userDetailInfo);
		return ResultMsg.success(result);
	}
    
    @Override
    /**
     * @ServiceHandler(memo = "获取操作有权限的菜单和操作")
     */
    public ResultMsg<AuthMenuResult> getAuthMenu(Long userId) {

        AuthMenuResult result = new AuthMenuResult();

        List<SysRole> roleList = authorityMapper.queryUserRoles(userId);
        if(roleList == null || roleList.size() == 0){
            result.setTreeNodeList(new ArrayList<MenuTreeInfo>());
            return ResultMsg.success(result);
        }

        List<Long> roleIdList = new ArrayList<Long>();
        for(SysRole role : roleList){
            roleIdList.add(role.getId());
        }
        List<SysMenu> authMenuList = authorityMapper.queryAuthMenu(roleIdList);
        //List<MenuTreeInfo> menuTreeList = getMenuTreeAndOperate(roleIdList).getData();//old
        
        List<SysMenu> allMenuList = authorityMapper.queryAllMenu();
		List<SysMenu> topList = this.getTopMenu(allMenuList);
		
		List<MenuTreeInfo> menuTreeList = new ArrayList<MenuTreeInfo>();
		for(SysMenu menu : topList){
		    MenuTreeInfo node = toTreeNode(menu, allMenuList, null);
		    menuTreeList.add(node);
		}
        
        removeNoAuthMenu(menuTreeList, authMenuList);
        removeAllNoChildFolder(menuTreeList);

        result.setTreeNodeList(menuTreeList);

        return ResultMsg.success(result);
    }
    

    /**
     * 删除没有权限的菜单
     * @param nodeList
     * @param authMenuList
     */
    public void removeNoAuthMenu(List<MenuTreeInfo> nodeList, List<SysMenu> authMenuList) {
        Iterator<MenuTreeInfo> it = nodeList.iterator();
        while(it.hasNext()){
            MenuTreeInfo node = it.next();
            if(MenuTypeEnum.FOLDER.code().equals(node.getMenuType())){
                if(node.getChild() != null && node.getChild().size() > 0){
                    removeNoAuthMenu(node.getChild(), authMenuList);
                }

            }else if (MenuTypeEnum.MENU.code().equals(node.getMenuType())){
                if(!hasAuth(node.getId(), authMenuList)){
                    it.remove();
                }
            }
        }
    }

    private boolean hasAuth(Long menuId, List<SysMenu> authMenuList){
        for(SysMenu menu : authMenuList){
            if(menu.getId().longValue() == menuId){
                return true;
            }
        }
        return false;
    }

    private boolean hasAuthForOperator(Long operatorId, List<SysMenuOperate> authOperates){
        for(SysMenuOperate menu : authOperates){
            if(menu.getId().longValue() == operatorId){
                return true;
            }
        }
        return false;
    }

    /**
     * 删除没有子菜单的空文件夹
     * @param nodeList
     */
    public void removeAllNoChildFolder(List<MenuTreeInfo> nodeList){
    	int totalNum = 5;
        for(int i = 0; i < totalNum; i ++){
        	//节点最大存在几级就得删除几次
            removeNoChildFolder(nodeList);
        }
    }

    private void removeNoChildFolder(List<MenuTreeInfo> nodeList){
        Iterator<MenuTreeInfo> it = nodeList.iterator();
        while(it.hasNext()){
            MenuTreeInfo node = it.next();

            if(MenuTypeEnum.FOLDER.code().equals(node.getMenuType())){
                if(node.getChild() == null || node.getChild().size() == 0){
                    it.remove();
                }else{
                    removeNoChildFolder(node.getChild());
                }
            }
        }
    }

    /**
     * 获取菜单树形结构,并且将按钮放到菜单栏目节点
     * @return
     */
    @Override
    public ResultMsg<List<MenuTreeInfo>> getMenuTreeAndOperate(List<Long> roleIdList) {
        if(roleIdList == null){
            roleIdList = new ArrayList<Long>();
        }
        if(roleIdList.size() == 0){
            roleIdList.add(-1L);
        }
        //查询用户有权限操作
        List<SysMenuOperate> authOperates = authorityMapper.queryAuthOperate(roleIdList);
        List<SysMenu> allMenuList = authorityMapper.queryAllMenu();

        Map<Long, List<MenuOperateInfo>> menuOperatorMap = new HashMap<Long, List<MenuOperateInfo>>(HashMapSizeConstant.HASH_MAP_SIZE);
        List<MenuOperateInfo> operatorList = authorityMapper.queryAllOperator();

        for (MenuOperateInfo operate : operatorList) {
            List<MenuOperateInfo> list = menuOperatorMap.get(operate.getMenuId());
            if (list == null) {
                list = new ArrayList<MenuOperateInfo>();
                menuOperatorMap.put(operate.getMenuId(), list);
            }
            if(hasAuthForOperator(operate.getId(), authOperates)){
                operate.setHasAuth(true);
            }else{
                operate.setHasAuth(false);
            }
            list.add(operate);
        }

        List<SysMenu> topList = this.getTopMenu(allMenuList);

        List<MenuTreeInfo> nodeList = new ArrayList<MenuTreeInfo>();
        for(SysMenu menu : topList){
            MenuTreeInfo node = toTreeNode(menu, allMenuList, menuOperatorMap);
            nodeList.add(node);
        }

        return ResultMsg.success(nodeList);
    }

    /**
     * 获取菜单树形结构
     * addBtn：是否将按钮数据设置到栏目节点
     * @return
     */
    @Override
    public ResultMsg<List<MenuTreeInfo>> getMenuTree() {
        List<SysMenu> allMenuList = authorityMapper.queryAllMenu();

        List<SysMenu> topList = this.getTopMenu(allMenuList);
        List<MenuTreeInfo> nodeList = new ArrayList<MenuTreeInfo>();
        for(SysMenu menu : topList){
            MenuTreeInfo node = toTreeNode(menu, allMenuList, null);
            nodeList.add(node);
        }

      //不需要将菜单上加载按钮属性
        Map<Long, List<MenuOperateInfo>> menuOperatorMap = new HashMap<Long, List<MenuOperateInfo>>(HashMapSizeConstant.HASH_MAP_SIZE);
        List<MenuOperateInfo> opearteList= sysMenuOperateMapper.queryOperateList();
        List<MenuOperateInfo> tmp = null;
        for(MenuOperateInfo operate : opearteList){
            tmp = menuOperatorMap.get(operate.getMenuId().longValue());
            if(tmp == null){
                tmp = new ArrayList<MenuOperateInfo>();
                menuOperatorMap.put(operate.getMenuId().longValue(), tmp);
            }
            tmp.add(operate);
        }

        addBtnToMenu(nodeList, menuOperatorMap);

        return ResultMsg.success(nodeList);
    }

    private void addBtnToMenu(List<MenuTreeInfo> menuTreeInfoList, Map<Long, List<MenuOperateInfo>> menuOperatorMap){
        for(MenuTreeInfo menuTreeInfo : menuTreeInfoList){
            if("MENU".equals(menuTreeInfo.getMenuType())){
                List<MenuTreeInfo> child = menuTreeInfo.getChild();
                if(child == null){
                    child = new ArrayList<>();
                }
                List<MenuOperateInfo> btns = menuOperatorMap.get(menuTreeInfo.getId());
                if(btns == null){
                    btns = new ArrayList<MenuOperateInfo>();
                }

                for(MenuOperateInfo btn : btns){
                    MenuTreeInfo m = new MenuTreeInfo();
                    m.from(btn);
                    m.setMenuName(btn.getOperateName());
                    m.setMenuType("BUTTON");
                    child.add(m);
                }
                menuTreeInfo.setChild(child);
            }

            List<MenuTreeInfo> child = menuTreeInfo.getChild();
            if(child != null && child.size() > 0){
                addBtnToMenu(child, menuOperatorMap);
            }
        }

    }

    private MenuTreeInfo toTreeNode(SysMenu menu, final List<SysMenu> allMenuList, Map<Long, List<MenuOperateInfo>> menuOperatorMap){
        MenuTreeInfo treeNode = new MenuTreeInfo();
        treeNode.from(menu);
        
        List<SysMenu> childMenuList = getChildMenu(menu.getId(), allMenuList);
        if(childMenuList == null || childMenuList.size() == 0){
            return treeNode;
        }

        List<MenuTreeInfo> childNodeList = new ArrayList<MenuTreeInfo>();
        for(SysMenu m : childMenuList){
            MenuTreeInfo node = toTreeNode(m, allMenuList, menuOperatorMap);
            childNodeList.add(node);
        }
        treeNode.setChild(childNodeList);
        return treeNode;
    }

    private List<SysMenu> getTopMenu(List<SysMenu> menuList){
        List<SysMenu> topList = new ArrayList<SysMenu>();
        menuList.forEach(obj -> {
            if(obj.getParentId() == -1){
                topList.add(obj);
            }
        });
        
        Collections.sort(topList, new Comparator<SysMenu>() {
            @Override
            public int compare(SysMenu u1, SysMenu u2) {
                int diff = u1.getSortNum() - u2.getSortNum();
                if (diff > 0) {//升序
                    return 1;
                }else if (diff < 0) {//降序
                    return -1;
                }
                return 0;
            }
        });
        
        return topList;
    }

    private List<SysMenu> getChildMenu(Long parentId, final List<SysMenu> allMenuList){
        List<SysMenu> childList = new ArrayList<SysMenu>();
        for(SysMenu m : allMenuList){
            if(m.getParentId().longValue() == parentId.longValue()){
                childList.add(m);
            }
        }
        childList.forEach(o -> {
            if(o.getSortNum() == null) {
                o.setSortNum(Integer.MAX_VALUE);
            }
        });
        Collections.sort(childList, new Comparator<SysMenu>() {
            @Override
            public int compare(SysMenu u1, SysMenu u2) {
                int diff = u1.getSortNum() - u2.getSortNum();
                if (diff > 0) {//升序
                    return 1;
                }else if (diff < 0) {//降序
                    return -1;
                }
                return 0;
            }
        });

        return childList;
    }

	



}
